package com.naiterui.ehp.bs.doctor.service.impl;

import cn.hutool.core.lang.Assert;
import com.naiterui.ehp.bp.domain.Doctor;
import com.naiterui.ehp.bp.domain.DoctorCharge;
import com.naiterui.ehp.bp.domain.DrChargeConfig;
import com.naiterui.ehp.bp.support.exception.BusinessException;
import com.naiterui.ehp.bp.utils.lang.ConfigUtil;
import com.naiterui.ehp.bp.utils.lang.StringUtil;
import com.naiterui.ehp.bs.doctor.exception.ExceptionCodes;
import com.naiterui.ehp.bs.doctor.repository.IDoctorChargeRepository;
import com.naiterui.ehp.bs.doctor.repository.IDoctorRepository;
import com.naiterui.ehp.bs.doctor.repository.IDrChargeConfigRepository;
import com.naiterui.ehp.bs.doctor.service.IChargeService;
import com.naiterui.ehp.bs.doctor.vo.ChargeVO;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.function.Function;
import java.util.stream.Collectors;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

/**
 * @author gaoliangliang
 * @date 2021/1/26 上午9:05
 **/
@Service
@RequiredArgsConstructor
@Slf4j
public class ChargeServiceImpl implements IChargeService {

    private final IDoctorRepository doctorRepository;
    private final IDoctorChargeRepository doctorChargeRepository;
    private final IDrChargeConfigRepository drChargeConfigRepository;

    @Override
    public ChargeVO getChargeInfoByType(Long doctorId, Integer type) {
        Doctor doctor = doctorRepository.get(doctorId);
        Assert.notNull(doctor, "医生用户信息获取失败;doctorId:{}", doctorId);
        DrChargeConfig chargeConfig = drChargeConfigRepository.findFirstByTypeAndDoctorTitle(type, doctor.getTitleId());
        Assert.notNull(chargeConfig, "医生收费服务设置获取失败;type:{},title:{}", type, doctor.getTitleId());
        DoctorCharge doctorCharge = doctorChargeRepository.findFirstByDoctorIdAndChargeType(doctorId, type);

        // 图文咨询默认价格列表(单位分) TODO 区分职级设置价格阶梯
        String chargeListStr = ConfigUtil.getString("consult.charge.list");
        List<Integer> chargeList = StringUtil.convertIntegerStr2List(chargeListStr, ",");

        return ChargeVO.builder()
            .charge(Optional.ofNullable(doctorCharge).map(DoctorCharge::getCharge).orElse(0))
            .chargeList(chargeList)
            .doctorId(doctorId)
            .maxCharge(chargeConfig.getMaxCharge())
            .minCharge(chargeConfig.getMinCharge())
            .type(type)
            .build();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void saveChargeInfo(Long doctorId, Integer type, Integer charge) throws BusinessException {
        Doctor doctor = doctorRepository.get(doctorId);
        Assert.notNull(doctor, "医生用户信息获取失败;doctorId:{}", doctorId);
        DrChargeConfig chargeConfig = drChargeConfigRepository.findFirstByTypeAndDoctorTitle(type, doctor.getTitleId());
        Assert.notNull(doctor, "医生收费服务设置获取失败;type:{},title:{}", type, doctor.getTitleId());
        //收费上下限校验
        if (chargeConfig.getMaxCharge() < charge || chargeConfig.getMinCharge() > charge) {
            log.error("saveChargeInfo error : doctorId={},type={},charge={}", doctorId, type, charge);
            throw new BusinessException(ExceptionCodes.CHARGE_CONSULT_OUTLIMIT);
        }

        DoctorCharge doctorCharge = doctorChargeRepository.findFirstByDoctorIdAndChargeType(doctorId, type);
        if (doctorCharge == null) {
            doctorCharge = new DoctorCharge(doctorId, type, charge, 0);
        }
        doctorCharge.setCharge(charge);
        doctorCharge.setChangedAt(new Date());
        doctorCharge.setChangedBy(doctorId + "");

        doctorChargeRepository.saveOrUpdate(doctorCharge);
    }

    @Override
    public Map<Long, Integer> getDoctorCharge(List<Long> doctorIdList, Integer type) {
        List<DoctorCharge> doctorChargeList = doctorChargeRepository.findByDoctorIdInAndChargeType(doctorIdList, type);
        Map<Long, Integer> chargeMap = doctorChargeList.stream()
            .collect(Collectors.toMap(DoctorCharge::getDoctorId, DoctorCharge::getCharge, (a, b) -> b));
        doctorIdList.forEach(doctorId -> chargeMap.computeIfAbsent(doctorId, (key) -> 0));
        return chargeMap;
    }

    @Override
    public List<ChargeVO> getChargeInfo(Long doctorId) {
        Doctor doctor = doctorRepository.get(doctorId);
        Assert.notNull(doctor, "医生用户信息获取失败;doctorId:{}", doctorId);
        // 图文咨询默认价格列表(单位分)
        String chargeListStr = ConfigUtil.getString("consult.charge.list");

        List<Integer> chargeList = StringUtil.convertIntegerStr2List(chargeListStr, ",");

        // 未认证，默认支持图文咨询、免费
        if (doctor.getTitleId() == null) {
            return Collections.singletonList(ChargeVO.builder()
                .charge(0)
                .chargeList(chargeList)
                .doctorId(doctorId)
                .maxCharge(999900)
                .minCharge(0)
                .type(DrChargeConfig.TYPE_MESSAGE)
                .build());
        }
        List<DrChargeConfig> chargeConfigs = drChargeConfigRepository.findByDoctorTitle(doctor.getTitleId());
        Map<Integer, DrChargeConfig> chargeConfigMap = chargeConfigs.stream()
            .collect(Collectors.toMap(DrChargeConfig::getType, Function.identity(), (a, b) -> b));
        Assert.notEmpty(chargeConfigs, "医生收费服务设置获取失败;title:{}", doctor.getTitleId());
        List<DoctorCharge> doctorCharges = doctorChargeRepository.findByDoctorId(doctorId);

        return doctorCharges.stream().map(doctorCharge -> ChargeVO.builder()
            .charge(doctorCharge.getCharge())
            .chargeList(chargeList)
            .doctorId(doctorId)
            .maxCharge(Optional.ofNullable(chargeConfigMap.get(doctorCharge.getChargeType())).map(DrChargeConfig::getMaxCharge).orElse(999900))
            .minCharge(Optional.ofNullable(chargeConfigMap.get(doctorCharge.getChargeType())).map(DrChargeConfig::getMinCharge).orElse(0))
            .type(doctorCharge.getChargeType())
            .build()).collect(Collectors.toList());
    }
}
